﻿using System;
using Mbs.ComponentModel.Container.Proxy;
using Mbs.Reflection;

namespace Mbs.ComponentModel.Container.Activation
{
    [Serializable]
    public class ProxyActivator : MarshalAndDisposableObject, IActivator
    {
        private readonly IActivator Real;

        public ProxyActivator(IActivator real)
        {
            Real = real;
        }

        public void Init(Action<Mbs.ComponentModel.Container.Metadata.IComponentInfo, object> onCreation)
        {
            Real.Init(onCreation);
        }

        public object Create(Mbs.ComponentModel.Container.Context.ICreateContext context)
        {
            var impType = context.Component.Implementation;
            if (impType.IsOpenGenericType())
                impType = impType.MakeCloseGenericType(context.GenericParameters);

            var Kernel = context.Kernel as IKernel;
            var proxyFactory = Kernel.Get<IProxyFactory>();
            bool createProxy = proxyFactory != null && proxyFactory.ShouldCreateProxy(context.Component);
            bool createInstance = true;

            object instance = null;

            if (createProxy == false && impType.IsAbstract)
            {
                throw new ActivatorException(
                    string.Format(
                        "Type {0} is abstract.\r\n As such, it is not possible to instansiate it as implementation of {1} service",
                        impType.FullName,
                        context.Component.Service.FullName));
            }


            if (createProxy)
            {
                createInstance = proxyFactory.RequiresTargetInstance(Kernel, context.Component);
            }

            if (createInstance)
            {
                try
                {
                    instance = Real.Create(context);
                }
                catch (Exception ex)
                {
                    throw new ActivatorException(
                        "ComponentActivator: could not instantiate " + impType.FullName, ex);
                }
            }

            if (createProxy)
            {
                try
                {
                    instance = proxyFactory.Create(context, instance);
                }
                catch (Exception ex)
                {
                    throw new ActivatorException("ComponentActivator: could not proxy " + impType.FullName, ex);
                }
            }

            return instance;
        }

      
    }
}
